<html><head><meta charset="utf-8"><title>22 ArrayBlockingQueue 源码解析-慕课专栏</title>
			<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1">
			<meta name="renderer" content="webkit">
			<meta property="qc:admins" content="77103107776157736375">
			<meta property="wb:webmaster" content="c4f857219bfae3cb">
			<meta http-equiv="Access-Control-Allow-Origin" content="*">
			<meta http-equiv="Cache-Control" content="no-transform ">
			<meta http-equiv="Cache-Control" content="no-siteapp">
			<link rel="apple-touch-icon" sizes="76x76" href="https://www.imooc.com/static/img/common/touch-icon-ipad.png">
			<link rel="apple-touch-icon" sizes="120x120" href="https://www.imooc.com/static/img/common/touch-icon-iphone-retina.png">
			<link rel="apple-touch-icon" sizes="152x152" href="https://www.imooc.com/static/img/common/touch-icon-ipad-retina.png">
			<link href="https://moco.imooc.com/captcha/style/captcha.min.css" rel="stylesheet">
			<link rel="stylesheet" href="https://www.imooc.com/static/moco/v1.0/dist/css/moco.min.css?t=201907021539" type="text/css">
			<link rel="stylesheet" href="https://www.imooc.com/static/lib/swiper/swiper-3.4.2.min.css?t=201907021539">
			<link rel="stylesheet" href="https://static.mukewang.com/static/css/??base.css,common/common-less.css?t=2.5,column/zhuanlanChapter-less.css?t=2.5,course/inc/course_tipoff-less.css?t=2.5?v=201907051055" type="text/css">
			<link charset="utf-8" rel="stylesheet" href="https://www.imooc.com/static/lib/ueditor/themes/imooc/css/ueditor.css?v=201907021539"><link rel="stylesheet" href="https://www.imooc.com/static/lib/baiduShare/api/css/share_style0_16.css?v=6aba13f0.css"></head>
			<body><div id="main">


<div class="main-con hide-menu">
    <!-- 左侧菜单 & 索引 -->
    
    <div class="right-content" style="padding-left: 0px;">
        <div class="container clearfix" id="top" style="width: 1134px; display: block;">
            
            
            <div class="center_con js-center_con l" style="width: 1134px;">
                <div class="article-con">
                                            <!-- 买过的阅读 -->
                        

                    
                    <div class="art-title" style="margin-top: 0px;">
                        22 ArrayBlockingQueue 源码解析
                    </div>
                    <div class="art-info clearfix">
                        
                        <span class="l">
                            更新时间：2019-11-07 10:48:29
                        </span>
                    </div>
                    <div class="art-top">
                                                <img src="https://img2.mukewang.com/5da483730001b51b06400359.jpg" alt="">
                                                                        <div class="famous-word-box">
                            <img src="https://www.imooc.com/static/img/column/bg-l.png" alt="" class="bg1 bg">
                            <img src="https://www.imooc.com/static/img/column/bg-r.png" alt="" class="bg2 bg">
                            <div class="famous-word">耐心和恒心总会得到报酬的。<p class="author">——爱因斯坦</p></div>
                        </div>
                                            </div>
                    <div class="art-content js-lookimg">
                        <div id="article_content">
                            <div class="cl-preview-section"><h3 id="引导语">引导语</h3>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">本小节我们来介绍本章最后一个队列：ArrayBlockingQueue。按照字面翻译，中文叫做数组阻塞队列，从名称上看，我们就比较清楚此阻塞队列底层使用的是数组。一说到数组，大家可能会想到 ArrayList 和 HashMap，举新增场景来说 ArrayList 通过 size ++ 找到新增的数组下标位置，HashMap 通过 hash 算法计算出下标位置，那么 ArrayBlockingQueue 是不是也是这两种方法呢？都不是，ArrayBlockingQueue 使用的是一种非常奇妙的方式，我们一起拭目以待。</p>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">全文为了方便说明，队头的说法就是数组头，队尾的说法就是数组尾。</p>
</div><div class="cl-preview-section"><h3 id="整体架构">1 整体架构</h3>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">我们从类注释上可以得到一些有用的信息：</p>
</div><div class="cl-preview-section"><h4 id="类注释" style="font-size: 26px;">1.1 类注释</h4>
</div><div class="cl-preview-section"><ol>
<li style="font-size: 20px; line-height: 38px;">有界的阻塞数组，容量一旦创建，后续大小无法修改；</li>
<li style="font-size: 20px; line-height: 38px;">元素是有顺序的，按照先入先出进行排序，从队尾插入数据数据，从队头拿数据；</li>
<li style="font-size: 20px; line-height: 38px;">队列满时，往队列中 put 数据会被阻塞，队列空时，往队列中拿数据也会被阻塞。</li>
</ol>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">从类注释上可以看出 ArrayBlockingQueue 和一般的数组结构的类不太一样，是不能够动态扩容的，如果队列满了或者空时，take 和 put 都会被阻塞。</p>
</div><div class="cl-preview-section"><h3 id="数据结构">1.2 数据结构</h3>
</div><div class="cl-preview-section"><pre class="  language-java"><code class="prism  language-java"><span class="token comment">// 队列存放在 object 的数组里面</span>
<span class="token comment">// 数组大小必须在初始化的时候手动设置，没有默认大小</span>
<span class="token keyword">final</span> Object<span class="token punctuation">[</span><span class="token punctuation">]</span> items<span class="token punctuation">;</span>

<span class="token comment">// 下次拿数据的时候的索引位置</span>
<span class="token keyword">int</span> takeIndex<span class="token punctuation">;</span>

<span class="token comment">// 下次放数据的索引位置</span>
<span class="token keyword">int</span> putIndex<span class="token punctuation">;</span>

<span class="token comment">// 当前已有元素的大小</span>
<span class="token keyword">int</span> count<span class="token punctuation">;</span>

<span class="token comment">// 可重入的锁</span>
<span class="token keyword">final</span> ReentrantLock lock<span class="token punctuation">;</span>

<span class="token comment">// take的队列</span>
<span class="token keyword">private</span> <span class="token keyword">final</span> Condition notEmpty<span class="token punctuation">;</span>

<span class="token comment">// put的队列</span>
<span class="token keyword">private</span> <span class="token keyword">final</span> Condition notFull<span class="token punctuation">;</span>
</code></pre>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">以上代码有两个关键的字段，takeIndex 和 putIndex，分别表示下次拿数据和放数据的索引位置。所以说在新增数据和拿数据时，都无需计算，就能知道应该新增到什么位置，应该从什么位置拿数据。</p>
</div><div class="cl-preview-section"><h3 id="初始化">2 初始化</h3>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">初始化时，有两个重要的参数：数组的大小、是否是公平，源码如下：</p>
</div><div class="cl-preview-section"><pre class="  language-java"><code class="prism  language-java"><span class="token keyword">public</span> <span class="token function">ArrayBlockingQueue</span><span class="token punctuation">(</span><span class="token keyword">int</span> capacity<span class="token punctuation">,</span> <span class="token keyword">boolean</span> fair<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>capacity <span class="token operator">&lt;=</span> <span class="token number">0</span><span class="token punctuation">)</span>
        <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">IllegalArgumentException</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>items <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Object</span><span class="token punctuation">[</span>capacity<span class="token punctuation">]</span><span class="token punctuation">;</span>
    lock <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ReentrantLock</span><span class="token punctuation">(</span>fair<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">// 队列不为空 Condition，在 put 成功时使用</span>
    notEmpty <span class="token operator">=</span> lock<span class="token punctuation">.</span><span class="token function">newCondition</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">// 队列不满 Condition，在 take 成功时使用</span>
    notFull <span class="token operator">=</span>  lock<span class="token punctuation">.</span><span class="token function">newCondition</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">从源码中我们可以看出，第二个参数是否公平，主要用于读写锁是否公平，如果是公平锁，那么在锁竞争时，就会按照先来先到的顺序，如果是非公平锁，锁竞争时随机的。</p>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">对于锁公平和非公平，我们举个例子：比如说现在队列是满的，还有很多线程执行 put 操作，必然会有很多线程阻塞等待，当有其它线程执行 take 时，会唤醒等待的线程，如果是公平锁，会按照阻塞等待的先后顺序，依次唤醒阻塞的线程，如果是非公平锁，会随机唤醒沉睡的线程。</p>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">所以说队列满很多线程执行 put 操作时，如果是公平锁，数组元素新增的顺序就是阻塞线程被释放的先后顺序，是有顺序的，而非公平锁，由于阻塞线程被释放的顺序是随机的，所以元素插入到数组的顺序也就不会按照插入的顺序了。</p>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">队列空时，也是一样的道理。</p>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">ArrayBlockingQueue 通过锁的公平和非公平，轻松实现了数组元素的插入顺序的问题。如果要实现这个功能，你会怎么做呢？会想到利用锁的功能么？其实这种思想我们在文中多次提到，当我们需要完成一件事情时，首先看看已有的 API 能不能满足，如果可以的话，通过继承和组合的方式来实现，ArrayBlockingQueue 就是组合了锁的功能。</p>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">初始化时，如果给定了原始数据的话，一定要注意原始数据的大小一定要小于队列的容量，否则会抛异常，如下图所示：</p>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;"><img class="" src="https://img.mukewang.com/5da9962c0001338b13541200.png" data-original="//img.mukewang.com/5da9962c0001338b13541200.png" alt="图片描述"><br>
我们写了一个 demo，报错如下：</p>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;"><img class="" src="https://img.mukewang.com/5da9963b00018d9022401200.png" data-original="//img.mukewang.com/5da9963b00018d9022401200.png" alt="图片描述"></p>
</div><div class="cl-preview-section"><h3 id="新增数据">3 新增数据</h3>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">数据新增都会按照 putIndex 的位置进行新增，源码如下：</p>
</div><div class="cl-preview-section"><pre class="  language-java"><code class="prism  language-java"><span class="token comment">// 新增，如果队列满，无限阻塞</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">put</span><span class="token punctuation">(</span>E e<span class="token punctuation">)</span> <span class="token keyword">throws</span> InterruptedException <span class="token punctuation">{</span>
    <span class="token comment">// 元素不能为空</span>
    <span class="token function">checkNotNull</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">final</span> ReentrantLock lock <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>lock<span class="token punctuation">;</span>
    lock<span class="token punctuation">.</span><span class="token function">lockInterruptibly</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">try</span> <span class="token punctuation">{</span>
        <span class="token comment">// 队列如果是满的，就无限等待</span>
        <span class="token comment">// 一直等待队列中有数据被拿走时，自己被唤醒</span>
        <span class="token keyword">while</span> <span class="token punctuation">(</span>count <span class="token operator">==</span> items<span class="token punctuation">.</span>length<span class="token punctuation">)</span>
            notFull<span class="token punctuation">.</span><span class="token function">await</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token function">enqueue</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span> <span class="token keyword">finally</span> <span class="token punctuation">{</span>
        lock<span class="token punctuation">.</span><span class="token function">unlock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">enqueue</span><span class="token punctuation">(</span>E x<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// assert lock.getHoldCount() == 1; 同一时刻只能一个线程进行操作此方法</span>
    <span class="token comment">// assert items[putIndex] == null;</span>
    <span class="token keyword">final</span> Object<span class="token punctuation">[</span><span class="token punctuation">]</span> items <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>items<span class="token punctuation">;</span>
    <span class="token comment">// putIndex 为本次插入的位置</span>
    items<span class="token punctuation">[</span>putIndex<span class="token punctuation">]</span> <span class="token operator">=</span> x<span class="token punctuation">;</span>
    <span class="token comment">// ++ putIndex 计算下次插入的位置</span>
    <span class="token comment">// 如果下次插入的位置，正好等于队尾，下次插入就从 0 开始</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">++</span>putIndex <span class="token operator">==</span> items<span class="token punctuation">.</span>length<span class="token punctuation">)</span>
        putIndex <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
    count<span class="token operator">++</span><span class="token punctuation">;</span>
    <span class="token comment">// 唤醒因为队列空导致的等待线程</span>
    notEmpty<span class="token punctuation">.</span><span class="token function">signal</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">从源码中，我们可以看出，其实新增就两种情况：</p>
</div><div class="cl-preview-section"><ol>
<li style="font-size: 20px; line-height: 38px;">
<p style="font-size: 20px; line-height: 38px;">本次新增的位置居中，直接新增，下图演示的是 putIndex 在数组下标为 5 的位置，还不到队尾，那么可以直接新增，计算下次新增的位置应该是 6；<br>
<img class="" src="https://img.mukewang.com/5da996520001b78412100296.png" data-original="//img.mukewang.com/5da996520001b78412100296.png" alt="图片描述"></p>
</li>
<li style="font-size: 20px; line-height: 38px;">
<p style="font-size: 20px; line-height: 38px;">新增的位置到队尾了，那么下次新增时就要从头开始了，示意图如下：<br>
<img class="" src="https://img.mukewang.com/5dc385f60001236510260354.png" data-original="//img.mukewang.com/5dc385f60001236510260354.png" alt="图片描述"></p>
</li>
</ol>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">上面这张图演示的就是这行代码：<code>if (++putIndex == items.length) putIndex = 0;</code></p>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">可以看到当新增到队尾时，下次新增会重新从队头重新开始。</p>
</div><div class="cl-preview-section"><h3 id="拿数据">4 拿数据</h3>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">拿数据都是从队头开始拿数据，源码如下：</p>
</div><div class="cl-preview-section"><pre class="  language-java"><code class="prism  language-java"><span class="token keyword">public</span> E <span class="token function">take</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> InterruptedException <span class="token punctuation">{</span>
    <span class="token keyword">final</span> ReentrantLock lock <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>lock<span class="token punctuation">;</span>
    lock<span class="token punctuation">.</span><span class="token function">lockInterruptibly</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">try</span> <span class="token punctuation">{</span>
        <span class="token comment">// 如果队列为空，无限等待</span>
        <span class="token comment">// 直到队列中有数据被 put 后，自己被唤醒</span>
        <span class="token keyword">while</span> <span class="token punctuation">(</span>count <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span>
            notEmpty<span class="token punctuation">.</span><span class="token function">await</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 从队列中拿数据</span>
        <span class="token keyword">return</span> <span class="token function">dequeue</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span> <span class="token keyword">finally</span> <span class="token punctuation">{</span>
        lock<span class="token punctuation">.</span><span class="token function">unlock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token keyword">private</span> E <span class="token function">dequeue</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">final</span> Object<span class="token punctuation">[</span><span class="token punctuation">]</span> items <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>items<span class="token punctuation">;</span>
    <span class="token comment">// takeIndex 代表本次拿数据的位置，是上一次拿数据时计算好的</span>
    E x <span class="token operator">=</span> <span class="token punctuation">(</span>E<span class="token punctuation">)</span> items<span class="token punctuation">[</span>takeIndex<span class="token punctuation">]</span><span class="token punctuation">;</span>
    <span class="token comment">// 帮助 gc</span>
    items<span class="token punctuation">[</span>takeIndex<span class="token punctuation">]</span> <span class="token operator">=</span> null<span class="token punctuation">;</span>
    <span class="token comment">// ++ takeIndex 计算下次拿数据的位置</span>
    <span class="token comment">// 如果正好等于队尾的话，下次就从 0 开始拿数据</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">++</span>takeIndex <span class="token operator">==</span> items<span class="token punctuation">.</span>length<span class="token punctuation">)</span>
        takeIndex <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
    <span class="token comment">// 队列实际大小减 1</span>
    count<span class="token operator">--</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>itrs <span class="token operator">!=</span> null<span class="token punctuation">)</span>
        itrs<span class="token punctuation">.</span><span class="token function">elementDequeued</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">// 唤醒被队列满所阻塞的线程</span>
    notFull<span class="token punctuation">.</span><span class="token function">signal</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> x<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">从源码中可以看出，每次拿数据的位置就是 takeIndex 的位置，在找到本次该拿的数据之后，会把 takeIndex 加 1，计算下次拿数据时的索引位置，有个特殊情况是，如果本次拿数据的位置已经是队尾了，那么下次拿数据的位置就要从头开始，就是从 0 开始了。</p>
</div><div class="cl-preview-section"><h3 id="删除数据">5 删除数据</h3>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">删除数据很有意思，我们一起来看下核心源码：</p>
</div><div class="cl-preview-section"><pre class="  language-java"><code class="prism  language-java"><span class="token comment">// 一共有两种情况：</span>
<span class="token comment">// 1：删除位置和 takeIndex 的关系：删除位置和 takeIndex 一样，比如 takeIndex 是 2， 而要删除的位置正好也是 2，那么就把位置 2 的数据置为 null ,并重新计算 takeIndex 为 3。</span>
<span class="token comment">// 2：找到要删除元素的下一个，计算删除元素和 putIndex 的关系</span>
<span class="token comment">// 如果下一个元素不是 putIndex，就把下一个元素往前移动一位</span>
<span class="token comment">// 如果下一个元素是 putIndex，把 putIndex 的值修改成删除的位置</span>
<span class="token keyword">void</span> <span class="token function">removeAt</span><span class="token punctuation">(</span><span class="token keyword">final</span> <span class="token keyword">int</span> removeIndex<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">final</span> Object<span class="token punctuation">[</span><span class="token punctuation">]</span> items <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>items<span class="token punctuation">;</span>
    <span class="token comment">// 情况1 如果删除位置正好等于下次要拿数据的位置</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>removeIndex <span class="token operator">==</span> takeIndex<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// 下次要拿数据的位置直接置空</span>
        items<span class="token punctuation">[</span>takeIndex<span class="token punctuation">]</span> <span class="token operator">=</span> null<span class="token punctuation">;</span>
        <span class="token comment">// 要拿数据的位置往后移动一位</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">++</span>takeIndex <span class="token operator">==</span> items<span class="token punctuation">.</span>length<span class="token punctuation">)</span>
            takeIndex <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
        <span class="token comment">// 当前数组的大小减一</span>
        count<span class="token operator">--</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>itrs <span class="token operator">!=</span> null<span class="token punctuation">)</span>
            itrs<span class="token punctuation">.</span><span class="token function">elementDequeued</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">// 情况 2</span>
    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
        <span class="token keyword">final</span> <span class="token keyword">int</span> putIndex <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>putIndex<span class="token punctuation">;</span>
        <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> removeIndex<span class="token punctuation">;</span><span class="token punctuation">;</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token comment">// 找到要删除元素的下一个</span>
            <span class="token keyword">int</span> next <span class="token operator">=</span> i <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>next <span class="token operator">==</span> items<span class="token punctuation">.</span>length<span class="token punctuation">)</span>
                next <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
            <span class="token comment">// 下一个元素不是 putIndex</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>next <span class="token operator">!=</span> putIndex<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token comment">// 下一个元素往前移动一位</span>
                items<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span> items<span class="token punctuation">[</span>next<span class="token punctuation">]</span><span class="token punctuation">;</span>
                i <span class="token operator">=</span> next<span class="token punctuation">;</span>
            <span class="token comment">// 下一个元素是 putIndex</span>
            <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
                <span class="token comment">// 删除元素</span>
                items<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span> null<span class="token punctuation">;</span>
                <span class="token comment">// 下次放元素时，应该从本次删除的元素放</span>
                <span class="token keyword">this</span><span class="token punctuation">.</span>putIndex <span class="token operator">=</span> i<span class="token punctuation">;</span>
                <span class="token keyword">break</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
        count<span class="token operator">--</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>itrs <span class="token operator">!=</span> null<span class="token punctuation">)</span>
            itrs<span class="token punctuation">.</span><span class="token function">removedAt</span><span class="token punctuation">(</span>removeIndex<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    notFull<span class="token punctuation">.</span><span class="token function">signal</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">删除数据的情况比较复杂，一共有两种情况，第一种情况是 takeIndex == removeIndex，我们画个示意图来看下处理方式：</p>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;"><img class="" src="https://img.mukewang.com/5da9967c0001f1a112600970.png" data-original="//img.mukewang.com/5da9967c0001f1a112600970.png" alt="图片描述"><br>
第二种情况又分两种：</p>
</div><div class="cl-preview-section"><ol>
<li style="font-size: 20px; line-height: 38px;">
<p style="font-size: 20px; line-height: 38px;">如果 removeIndex + 1 != putIndex 的话，就把下一个元素往前移动一位，示意图如下：<br>
<img class="" src="https://img.mukewang.com/5da996880001782712280958.png" data-original="//img.mukewang.com/5da996880001782712280958.png" alt="图片描述"></p>
</li>
<li style="font-size: 20px; line-height: 38px;">
<p style="font-size: 20px; line-height: 38px;">如果 removeIndex + 1 == putIndex 的话，就把 putIndex 的值修改成删除的位置，示意图如下：</p>
</li>
</ol>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;"><img class="" src="https://img.mukewang.com/5da9969c0001254d12300940.png" data-original="//img.mukewang.com/5da9969c0001254d12300940.png" alt="图片描述"></p>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">ArrayBlockingQueue 的删除方法其实还蛮复杂的，需要考虑到很多特殊的场景。</p>
</div><div class="cl-preview-section"><h3 id="总结">6 总结</h3>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">ArrayBlockingQueue 底层是有界的数组，整体来说，和其它队列差别不多，需要注意的是，当 takeIndex、putIndex 到队尾的时候，都会重新从 0 开始循环，这点是比较特殊的，在我们学习源码时，需要特别注意。</p>
</div>}
                        </div>
                    </div>
                                            <!-- 买过的阅读 -->
                        <div class="art-next-prev clearfix">
                                                                                                <!-- 已买且开放 或者可以试读 -->
                                    <a href="/read/47/article/863">
                                                                    <div class="prev l clearfix">
                                        <div class="icon l">
                                            <i class="imv2-arrow3_l"></i>
                                        </div>
                                        <p>
                                            21 DelayQueue 源码解析  
                                        </p>
                                    </div>
                                </a>
                                                                                                                            <!-- 已买且开放 或者可以试读 -->
                                    <a href="/read/47/article/865">
                                                                    <div class="next r clearfix">
                                        <p>
                                            23 队列在源码方面的面试题  
                                        </p>
                                        <div class="icon r">
                                            <i class="imv2-arrow3_r"></i>
                                        </div>

                                    </div>
                                </a>
                                                    </div>
                                    </div>
                <div class="comments-con js-comments-con" id="coments_con">
                </div>

                
            </div>
            
            
            

        </div>
    </div>
</div>

<div class="modal modal-jiaQun-new hide" id="modal-jiaQun">
    <div class="inner" style="">
        <div class="modal-close js-close-jiaQun">
            <i class="imv2-close"></i>
        </div>
        <div class="content">
            <img src="https://img1.mukewang.com/5d634d40000119e505400602.jpg">
            <div class="right-info">
                <div class="title">
                    扫码加入慕课Java核心用户群
                </div>
                <div class="desc">
                                            <p class="mb6">验证信息：<span id="joincode">1909271435058473</span><span class="copy js-copy-joincode">复制</span></p>
                                        <p class="mb6">QQ讨论群号：906691736</p>
                                            <p>QQ群URL：<a href="https://jq.qq.com/?_wv=1027&amp;k=55RtSbJ" target="_blank">点击访问</a></p>
                                    </div>
            </div>
            <p class="tip">若遇到搜索不到QQ群或加群失败，请联系客服邮箱:kf@imooc.com</p>
        </div>
    </div>
</div>
 
<!-- 专栏介绍页专栏评价 -->

<!-- 专栏介绍页底部三条评价 -->

<!-- 专栏阅读页弹层目录和介绍页页面目录 -->

<!-- 专栏阅读页发布回复 -->

<!-- 专栏阅读页发布评论 -->

<!-- 专栏阅读页底部评论 -->

<!-- 专栏阅读 单个 评论 -->

<!-- 新增回复和展开三条以外回复 -->

<!-- 立即订阅的弹窗 -->












</div></body></html>